package tv.accedo.achi.dao;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.stereotype.Component;

import tv.accedo.achi.model.Achi;
import tv.accedo.achi.model.Badge;
import tv.accedo.achi.model.User;

/**
 * A dao class with badge model database operations
 * @author Bo Liang
 *
 */

@Component
public class BadgeDao {

	private SessionFactory sessionFactory; //injection
	private Badge badge; //injection
	private User user; //injection
	private Achi achi; //injection

	/**
	 * Add badge to user object.
	 * <p>add badge object to the user objcet's property badge Set<br>
	 * @param username 	user name
	 * @param badge_sn 	badge serial number
	 * @return			true/false
	 */
	public boolean addBadgeToUser(String username, String badge_sn) {
		Session session = null; 
		Set<Badge> badges = new HashSet<Badge>(); 
		try {
//			session = SessionFactoryUtil.getSessionFactory().openSession(); 
			session = sessionFactory.openSession();
			session.beginTransaction();
			
			// get the user object by using username
			Query query = session.createQuery("from User user where user.username = ?")
						  .setParameter(0, username); 
			user = (User) query.uniqueResult(); 
			
			// get the badge object by using badge_sn
			query = session.createQuery("from Badge badge where badge.badge_sn = ?")
					.setParameter(0, badge_sn); 
			badge = (Badge)query.uniqueResult(); 
			
			// add the badge to user
			badges = user.getBadges(); 
			badges.add(badge);
			user.setBadges(badges); 
			
			session.save(user); 
			session.getTransaction().commit();
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
//			SessionFactoryUtil.closeSession(session);
			session.close();
		}
		
		return true;
	}
	
	/**
	 * Get badge object by using this badge's serial number
	 * @param badge_sn	badge serial number
	 * @return			badge object
	 */
	public Badge getBadgeByBadgesn(String badge_sn) {
		Session session = null; 
		try {
//			session = SessionFactoryUtil.getSessionFactory().openSession(); 
			session = sessionFactory.openSession();
			Query query = session.createQuery("from Badge badge where badge.badge_sn = ?")
					.setParameter(0, badge_sn); 
			badge = (Badge)query.uniqueResult();  
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
//			SessionFactoryUtil.closeSession(session);
			session.close();
		}
		return badge;  
	}
	
	/**
	 * Get badges id by using achievement id.
	 * <p> one achievement may related several badges,
	 * get these badge's id with a list format data
	 * 
	 * @param achi_id	achievement id
	 * @return			List with badge's id
	 */
	@SuppressWarnings("unchecked")
	public List<Integer> getBadgesIdByAchiId(int achi_id) {
		List<Integer> badgeIdList = new ArrayList<Integer>();
		Session session = null;
		try {
//			session = SessionFactoryUtil.getSessionFactory().openSession(); 
			session = sessionFactory.openSession();
			Query query = session.createSQLQuery("select badge_id from t_badge_achi where achi_id = ?")
					.setParameter(0, achi_id); 
			badgeIdList = query.list(); 
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
//			SessionFactoryUtil.closeSession(session);
			session.close();
		}
		return badgeIdList; 
	}
	
	/**
	 * Get one specific badge's all achievements by using this badge's serial number.
	 * @param badge_sn	badge serial number
	 * @return			Set with achievements
	 */
	public Set<Achi> getAchisByBadgesn(String badge_sn) {
//		List<Achi> achiList = new ArrayList<Achi>();
		Set<Achi> achiSet = new HashSet<Achi>(); 
		Session session = null; 
		try {
//			session = SessionFactoryUtil.getSessionFactory().openSession(); 
			session = sessionFactory.openSession();
			Query query = session.createQuery("from Badge badge where badge.badge_sn = ?")
					.setParameter(0, badge_sn); 
			badge = (Badge)query.uniqueResult(); 
			achiSet = badge.getAchis(); 
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
//			SessionFactoryUtil.closeSession(session);
			session.close();
		}
		return achiSet; 
	}
	
	/**
	 * Get all badge objects which badge is belonged to one specific user by using user id.
	 * @param user_id	user id
	 * @return			List with badge object
	 */
	@SuppressWarnings("unchecked")
	public List<Badge> getBadgesByUserId(int user_id) {
		List<Integer> badgeIdList = new ArrayList<Integer>(); 
		List<Badge> badgeList = new ArrayList<Badge>(); 
		Session session = null; 
		try {
//			session = SessionFactoryUtil.getSessionFactory().openSession(); 
			session = sessionFactory.openSession();
			
			// get all badge's id which badge is belonged to this user
			Query query = session.createSQLQuery("select badge_id from t_user_badge where user_id = ?")
					.setParameter(0, user_id); 
			badgeIdList = query.list();  
			
			// iterate all badge id and then get the badge object and add to the badge list
			for (Iterator<Integer> iter = badgeIdList.iterator(); iter.hasNext(); ) {
				int badge_id = iter.next();
				query = session.createQuery("from Badge badge where badge.id = ?")
					.setParameter(0, badge_id); 
				badge = (Badge)query.uniqueResult();
				badgeList.add(badge); 
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
//			SessionFactoryUtil.closeSession(session);
			session.close();
		}
		
		return badgeList; 
	}
	
	/**
	 * Get all badge objects from the database.
	 * @return List with badge object
	 */
	@SuppressWarnings("unchecked")
	public List<Badge> getAllBadges() {
		List<Badge> badgeList = new ArrayList<Badge>(); 
		Session session = null;
		try {
//			session = SessionFactoryUtil.getSessionFactory().openSession(); 
			session = sessionFactory.openSession(); 
			Query query = session.createQuery("from Badge badge"); 
			badgeList = query.list();
		
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
//			SessionFactoryUtil.closeSession(session);
			session.close();
		}		
		return badgeList;
	}
	
	/**
	 * Get the user's all unlocked badge objects by using user id.
	 * @param user_id	user id
	 * @return			List with badge object
	 */
	@SuppressWarnings("unchecked")
	public Map<Integer, String> getUnlockedBadgesIdByUserId(int user_id) {
		List<Integer> unlockedBadgeIdList = new ArrayList<Integer>();
		List<Integer> badgeIdList = new ArrayList<Integer>();
		Map<Integer, String> returnMap = new HashMap<Integer, String>();
		int badge_id;
		Session session = null; 
		try {
//			session = SessionFactoryUtil.getSessionFactory().openSession(); 
			session = sessionFactory.openSession();
			Query query = session.createSQLQuery("select badge_id from t_user_badge where user_id = ? and unlock_flag = 1")
					.setParameter(0, user_id); 
			unlockedBadgeIdList = query.list();  
			query = session.createSQLQuery("select badge_id from t_user_badge where user_id = ?")
					.setParameter(0, user_id); 
			badgeIdList = query.list();
			
			for (Iterator<Integer> iter = badgeIdList.iterator(); iter.hasNext(); ) {
				badge_id = iter.next(); 
				if (unlockedBadgeIdList.contains(badge_id)) {
					returnMap.put(badge_id, "finished");
				} else {
					returnMap.put(badge_id, "playing");
				}
			}	
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
//			SessionFactoryUtil.closeSession(session);
			session.close();
		}
		return returnMap; 
	}
	
	public User getUser() {
		return user;
	}

	@Resource
	public void setUser(User user) {
		this.user = user;
	}

	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	@Resource
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	public Badge getBadge() {
		return badge;
	}

	@Resource
	public void setBadge(Badge badge) {
		this.badge = badge;
	}

	public Achi getAchi() {
		return achi;
	}

	@Resource
	public void setAchi(Achi achi) {
		this.achi = achi;
	}
	
	
}
